package com.judian.smart.netty;

import android.content.Intent;
import android.util.Log;

import com.judian.smart.R;
import com.judian.smart.activity.MainActivity;
import com.judian.smart.base.MyApplication;
import com.judian.smart.interfaces.OnSocketConnectListener;
import com.judian.smart.model.GateWay;
import com.judian.smart.model.Master;
import com.judian.smart.model.ServiceInfo;
import com.judian.smart.service.GateWayService;
import com.judian.smart.socket.ISocketCode;
import com.judian.smart.util.AppTools;
import com.judian.smart.util.MasterUtils;
import com.judian.smart.util.RAKParams;
import com.judian.smart.util.ServiceUtils;
import com.judian.smart.util.SystemInfo;

import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.timeout.IdleStateHandler;

// 使用Netty进行Socket连接
public class NettySocketClient {
    private static final String TAG = NettySocketClient.class.getSimpleName();
    private Channel channel = null;
    private int readerIdleSeconds = 0;
    private Thread send = null;
    private int writerIdleSeconds = 0;
    private int allIdleSeconds = 300;
    private OnSocketConnectListener CoallBack = null;
    private boolean mSocketFlag;

    private Vector<String> datas = new Vector<>();
    private final Object sendLock = new Object();

    private Timer mTimer1;
    private Timer mTimer2;
    private Timer mTimer3;


    public void setSocketFlag(boolean socketFlag) {
        mSocketFlag = socketFlag;
        if (!mSocketFlag) {
            Log.d(TAG, "setSocketFlag: socket断开连接");
            MainActivity.getInstance().sendBroadcast(new Intent("GateWayIsLineReceiver").putExtra("gateway_connect", false));
        }
    }

    public void setConnectorHost(String connectorHost) {
        NettySocketClient.connectorHost = connectorHost;
    }

    private static String connectorHost = "112.74.56.95:2020";
    private static NettySocketClient instans;

    public NettySocketClient(String connectorHost) {
        NettySocketClient.connectorHost = connectorHost;
    }

    public static synchronized NettySocketClient getInstans() {
        if (instans == null) {
            ServiceInfo info = ServiceUtils.getServiceInfo();
            String loginHost = info.getIP() + ":" + info.getPort();
            if (SystemInfo.getSSID(MyApplication.getInstance()).startsWith("RAK")) {
                loginHost = "192.168.7.1:25000";
            }
            instans = new NettySocketClient(loginHost);
        }
        return instans;
    }

    public boolean isConnect() {
        /* && channel.isActive()*/
        return channel != null;
    }

    public void disConnect() {
        if (channel != null) {
            datas.clear();
            try {
                channel.disconnect();
                channel = null;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (SystemInfo.getSSID(MyApplication.getInstance()).startsWith("RAK")) {
            connectorHost = "192.168.7.1:25000";
        } else {
            ServiceInfo info = ServiceUtils.getServiceInfo();
            connectorHost = info.getIP() + ":" + info.getPort();
        }
    }

    public void connect() {
        if (!mSocketFlag) {
            if (StringUtils.isNotBlank(connectorHost) && connectorHost.contains(":")) {
                String[] host = connectorHost.split(":");
                if (host.length == 2) {
                    channel = connect(host[0], Integer.valueOf(host[1]));
                    if (channel != null) {
                        if (CoallBack != null) {
                            CoallBack.onSuccess();
                            if (send == null) {
                                send = new Thread(new Send());
                                send.start();
//                                connectSucToHandle();   //连接成功后发送心跳包和连接成功和获取网关状态指令
                            }
                        }
                    } else {
                        if (mTimer3 == null) {
                            connectFailHandle();
                        }
                    }
                }
            }
        }
    }

    private Channel connect(String host, int port) {
        try {
            EventLoopGroup group = new NioEventLoopGroup();
            Bootstrap b = new Bootstrap();
            b.group(group).channel(NioSocketChannel.class).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000).option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline()
                                    // receive
                                    .addLast(new LineBasedFrameDecoder(Integer.MAX_VALUE))
                                    .addLast(new MessageDecoder())
                                    // send
                                    .addLast(new MessageEncoder())
                                    .addLast("timeout", new IdleStateHandler(readerIdleSeconds, writerIdleSeconds, allIdleSeconds))
                                    // handler
                                    .addLast(new DeviceChannelInboundHandler());
                        }
                    });
            // 发起异步连接操作
            return b.connect(host, port).sync().channel();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public void connectSucToHandle() {

        if (mTimer3 != null) {
            mTimer3.cancel();
            mTimer3 = null;
        }

        if (SystemInfo.getSSID(MyApplication.getInstance()).startsWith("RAK")) {
            String resultStr = RAKParams.getParams("Login", "00000000", 1);
            MyApplication.getInstance().sendBroadCast(resultStr);
        } else {
            Login();
        }


        ///// 发送心跳包
        mTimer1 = new Timer();
        TimerTask timerTask1 = new TimerTask() {
            @Override
            public void run() {

                if (SystemInfo.getSSID(MyApplication.getInstance()).startsWith("RAK")) {
                    Line();
                    String resultStr = RAKParams.getParams("Line", "00000000", 1);
                    MyApplication.getInstance().sendBroadCast(resultStr);
                } else {
                    Line();
                }

            }
        };
        mTimer1.schedule(timerTask1, 0, 30000);


        /////  计时器60秒后告诉服务器一直在连接    还有获取网关状态
        mTimer2 = new Timer();
        TimerTask timerTask2 = new TimerTask() {
            @Override
            public void run() {
                List<GateWay> gateWayList = GateWayService.list;
                if (!gateWayList.isEmpty()) {
                    for (GateWay gateWay : gateWayList) {
                        if (gateWay.getTypeId() <= 3) {
                            String resultCode = ISocketCode.setConnect(gateWay.getGatewayID(), gateWay.getUserName(), gateWay.getUserPassWord(), gateWay.getIsCurrent());
                            sendData(resultCode);
                        }
                    }
                }
            }
        };
        mTimer2.schedule(timerTask2, 0, 60000);
    }

    public void connectFailHandle() {

        if (mTimer1 != null) {
            mTimer1.cancel();
            mTimer1 = null;
        }

        if (mTimer2 != null) {
            mTimer2.cancel();
            mTimer2 = null;
        }

        if (mTimer3 != null) {
            mTimer3.cancel();
            mTimer3 = null;
        }

        if (null != channel) {
            channel.close();
        }

        mTimer3 = new Timer();
        TimerTask timerTask3 = new TimerTask() {
            @Override
            public void run() {
                connect();
            }
        };
        mTimer3.schedule(timerTask3, 0, 12000);
    }

    //发码
    public void sendData(String msg) {
        if (channel != null) {
            synchronized (sendLock) {
                datas.add(msg);
                sendLock.notify();
            }
        } else {
            if (mTimer3 == null) {
                connectFailHandle();
            }
        }
    }

    private class Send implements Runnable {
        public void run() {
            Log.e("socket", "S_run" + AppTools.getCurrentTime());
            try {
                while (true) {
                    while (datas.size() > 0) {
                        try {
                            String result = datas.remove(0);
                            channel.writeAndFlush(result).sync();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    synchronized (sendLock) {
                        sendLock.wait();
                    }
                }
            } catch (Exception e1) {
                if (mTimer3 == null) {
                    connectFailHandle();
                }
            }
        }
    }

    private void Login() {
        Master masterL = MasterUtils.getMaster(MyApplication.getInstance());
        sendData(ISocketCode.setLogin(masterL.getMn(), masterL.getPw(), masterL.getOr(), masterL.getOp(), 1));
    }

    private void Line() {
        Master masterName = MasterUtils.getMaster(MyApplication.getInstance());
        String result = ISocketCode.setLine(masterName.getMn(), masterName.getPw(), masterName.getOr(), masterName.getOp(), 1);
        sendData(result);
    }

    public void quite() {
        Log.e("NetCmd", AppTools.getCurrentTime() + "________quit");
        String result = ISocketCode.setForwardOut();
        sendData(result);
        if (channel != null) {
            datas.clear();
            try {
                channel.disconnect();
                channel = null;
//                CoallBack.OnDisConnect();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void connectGateway(int IsSendCmd) {
        List<GateWay> gateWayList = GateWayService.list;
        if (gateWayList != null && gateWayList.size() > 0) {
            for (int i = 0; i < gateWayList.size(); i++) {
                final GateWay gateWay = gateWayList.get(i);
                if (gateWay.getTypeId() < 3) {
                    boolean SendCmdFlag = true;
                    if (IsSendCmd == 1) {
                        if (gateWay.getState().equals(MyApplication.getInstance()
                                .getString(R.string.gateWayLine))) {
                            SendCmdFlag = false;
                        }
                    }
                    if (SendCmdFlag) {
                        if (SystemInfo.getSSID(MyApplication.getInstance()).startsWith("RAK")) {
                            if (gateWay.getTypeId() == 1) {
                                String resultStr = RAKParams.getParams("Connect", gateWay.getGatewayID(), 100);
                                MyApplication.getInstance().sendBroadCast(resultStr);
                            } else {
                                String resultStr = RAKParams.getParams("Connect", gateWay.getGatewayID(), 9);
                                MyApplication.getInstance().sendBroadCast(resultStr);
                            }
                        } else {
                            String resultCode = ISocketCode.setConnect(
                                    gateWay.getGatewayID(),
                                    gateWay.getUserName(),
                                    gateWay.getUserPassWord(),
                                    gateWay.getIsCurrent());
                            sendData(resultCode);
                        }
                    }
                }
            }
        }
    }

    public void setCoallBack(OnSocketConnectListener coallBack) {
        CoallBack = coallBack;
    }
}
